﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.IO;

namespace Toolkit.Web.Infastructure
{
    public class HtmlTemplate<T> where T : class
    {
        private IHtmlString _innerHtml;
        private Action<T, IViewComponentWriter> _actionTemplate;
        private Func<T, object> _inlineTemplate;

        public IHtmlString InnerHtml
        {
            get
            {
                return _innerHtml;
            }
            set
            {
                _actionTemplate = null;
                _inlineTemplate = null;
                _innerHtml = value;
            }
        }

        public Action<T, IViewComponentWriter> ActionTemplate
        {
            get
            {
                return _actionTemplate;
            }
            set
            {
                _innerHtml = null;
                _inlineTemplate = null;
                _actionTemplate = value;
            }
        }

        public Func<T, object> InlineTemplate
        {
            get
            {
                return _inlineTemplate;
            }
            set
            {
                _innerHtml = null;
                _actionTemplate = null;
                _inlineTemplate = value;
            }
        }

        public bool HasValue()
        {
            return InnerHtml != null || InlineTemplate != null || ActionTemplate != null;
        }

        public void Apply(T dataItem, IHtmlNode node)
        {
            if (!HasValue())
            {
                return;
            }

            if (InnerHtml != null)
            {
                node.InnerHtml = InnerHtml.ToHtmlString();
            }
            else if (InlineTemplate != null)
            {
                node.Template = (writer) => { writer.Write(InlineTemplate(dataItem)); };
            }
            else if (ActionTemplate != null)
            {
                node.Template = (writer) => { ActionTemplate(dataItem, writer); };
            }
        }

        public string ToHtmlString(T dataItem)
        {
            if (!HasValue())
            {
                return null;
            }

            string value = null;

            if (InnerHtml != null)
            {
                value = InnerHtml.ToHtmlString();
            }
            else if (InlineTemplate != null)
            {
                // Note: Anything written out to the response will be ignored with inline templates.
                value = InlineTemplate(dataItem).ToString();
            }
            else if (ActionTemplate != null)
            {
                using (TextWriter writer = new StringWriter())
                {
                    ActionTemplate(dataItem, new ViewComponentWriter(writer));
                    value = writer.ToString();
                    writer.Dispose();
                }
            }

            return value;
        }
    }

    public class HtmlTemplate : HtmlTemplate<object>
    {
        private Action<IViewComponentWriter> _contentTemplate;

        public Action<IViewComponentWriter> ContentTemplate
        {
            get
            {
                return _contentTemplate;
            }
            set
            {
                _contentTemplate = value;

                if (value != null)
                {
                    ActionTemplate = (template, writer) => { _contentTemplate(writer); };
                }
                else
                {
                    ActionTemplate = null;
                }
            }
        }

        public void Apply(IHtmlNode node)
        {
            Apply(null, node);
        }

        public string ToHtmlString()
        {
            return ToHtmlString(null);
        }
    }
}
